#ifndef _MEMBERSHIP_HPP
#define _MEMBERSHIP_HPP 1

#include <string>
#include <vector>
#include <boost/shared_ptr.hpp>
#include "Principal.hpp"
#include "../util/Role.hpp"
#include "Properties.hpp"
#include "../OrderParameters.hpp"

namespace BFT
{
  namespace membership
  {
    class Membership
    {

    public:
			
      /**
       * This constructor receives 3 arguments:
       * configFilename : path to the config file
       * role : can be in the set {order, exec, client}
       * id : a number from 1 to k, where k is the maximum id possible for that role
       */
      Membership(std::string configFileName, BFT::util::Role _role, int _id);
			
      void checkIdWithinRange(int _range);

      //each principal is wrapped in a shared pointer
      //a vector is used to contain an array of shared pointers to principals
      //finally, a shared pointer wrap the vector
      boost::shared_ptr< std::vector< boost::shared_ptr<Principal> > > getFilterNodes();
      boost::shared_ptr< std::vector< boost::shared_ptr<Principal> > > getOrderNodes();
      boost::shared_ptr< std::vector< boost::shared_ptr<Principal> > > getExecNodes();
      boost::shared_ptr< std::vector< boost::shared_ptr<Principal> > > getClientNodes();
      boost::shared_ptr< std::vector< boost::shared_ptr<Principal> > > getMyInterfaces();
      boost::shared_ptr< std::vector< boost::shared_ptr<Principal> > > getMyInterfaces(BFT::util::Role _role);

      boost::shared_ptr<Principal> getFilterNode(int _id);
      boost::shared_ptr<Principal> getOrderNode(int _id);
      boost::shared_ptr<Principal> getExecNode(int _id);
      boost::shared_ptr<Principal> getClientNode(int _id);

      boost::shared_ptr<Principal> getNode(BFT::util::Role _role, int _id);

      //RSAPublicKey getMyPublicKey();
      //RSAPrivateKey getMyPrivateKey();
      //Mac getMyMac();
			
      int getMyId();
      BFT::util::Role getMyRole();

    protected:
			
      BFT::util::Role role;
      int id;
      std::string myPrivateKeyString;
      std::string myPublicKeyString;
			
      //TODO
      //RSAPublicKey myPublicKey;
      //RSAPrivateKey myPrivateKey;
      //Mac myMac;

      //each principal is wrapped in a shared pointer
      //a vector is used to contain an array of shared pointers to principals
      //finally, a shared pointer wraps the vector
      boost::shared_ptr< std::vector< boost::shared_ptr<Principal> > > filterNodes; 
      boost::shared_ptr< std::vector< boost::shared_ptr<Principal> > > orderNodes;
      boost::shared_ptr< std::vector< boost::shared_ptr<Principal> > > execNodes;
      boost::shared_ptr< std::vector< boost::shared_ptr<Principal> > > clientNodes;
      boost::shared_ptr< std::vector< boost::shared_ptr<Principal> > > myInterfaces;

    private:
      //support for different threads handling the network interaction for each role
      boost::shared_ptr< std::vector< boost::shared_ptr<Principal> > > myFilterInterfaces; 
      boost::shared_ptr< std::vector< boost::shared_ptr<Principal> > > myOrderInterfaces;
      boost::shared_ptr< std::vector< boost::shared_ptr<Principal> > > myExecInterfaces;
      boost::shared_ptr< std::vector< boost::shared_ptr<Principal> > > myClientInterfaces;
			
    };

    inline 	boost::shared_ptr< std::vector< boost::shared_ptr<Principal> > > Membership::getFilterNodes() {return filterNodes;}
    inline 	boost::shared_ptr< std::vector< boost::shared_ptr<Principal> > > Membership::getOrderNodes() {return orderNodes;}
    inline 	boost::shared_ptr< std::vector< boost::shared_ptr<Principal> > > Membership::getExecNodes() {return execNodes;}		
    inline 	boost::shared_ptr< std::vector< boost::shared_ptr<Principal> > > Membership::getClientNodes() {return clientNodes;}

    inline boost::shared_ptr<Principal> Membership::getFilterNode(int _id) {return filterNodes.get()->at(_id);}
    inline boost::shared_ptr<Principal> Membership::getOrderNode(int _id) {return orderNodes.get()->at(_id);}
    inline boost::shared_ptr<Principal> Membership::getExecNode(int _id) {return execNodes.get()->at(_id);}
    inline boost::shared_ptr<Principal> Membership::getClientNode(int _id){return clientNodes.get()->at(_id);}
		
    inline int Membership::getMyId() {return id;}
    inline BFT::util::Role Membership::getMyRole() {return role;}
		
  }//namespace membership
}//namespace BFT

#endif
